﻿using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;

namespace Microsoft.Reputation.Tests.FrontEndCommon
{
    public static class LogHelper
    {
        /// <summary>
        /// This function takes in the location of a file share and returns 
        /// the name of latest log file from that share.
        /// </summary>
        /// <param name="logShareLocation"></param>
        /// <returns></returns>
        public static string FindLatestLogFile(string logShareLocation)
        {
            DirectoryInfo logDir = new DirectoryInfo(logShareLocation);
            if (!logDir.Exists)
            {
                throw new Exception("Log directory location not found");
            }

            FileInfo[] files = logDir.GetFiles();

            if (files.Length == 0)
            {
                throw new Exception("Log directory is empty");
            }
            FileInfo latestLogFile = files[0];
            foreach (FileInfo file in files)
            {
                if (DateTime.Compare(file.LastWriteTime, latestLogFile.LastWriteTime) > 0)
                {
                    latestLogFile = file;
                }
            }
            return latestLogFile.FullName;
        }

        /// <summary>
        /// This function takes a XML file name and a node name and returns the data 
        /// contained within the first instance of that node-name in XML file
        /// </summary>
        /// <param name="fileName"> Name of the file </param>
        /// <param name="nodeName"> node to read </param>
        /// <returns> string containing log entry </returns>
        public static string GetLogData(string fileName, string nodeName)
        {
            XDocument logFile = XDocument.Load(fileName);
            XElement element = logFile.Element(nodeName);
            if (null == element)
            {
                string exceptionMessage = string.Format("No element of type {0} found in the log file", nodeName);
                throw new Exception(exceptionMessage);
            }
            return element.ToString();
        }

        /// <summary>
        /// Modify a particular value in the config file
        /// </summary>
        /// <param name="fileLocation"></param>
        /// <param name="sectionName"></param>
        /// <param name="subsectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="newValue"></param>
        /// <returns></returns>
        public static bool ModifyConfigValue(string fileLocation, string sectionName,
                        string subsectionName, string keyName, string newValue)
        {
            XDocument doc = XDocument.Load(fileLocation);

            XElement section = null;
            IEnumerable<XNode> nodes =
                from node in doc.DescendantNodes()
                select node;
            foreach (XNode node in nodes)
            {
                if (node is XElement)
                {
                    section = node as XElement;
                    if (sectionName.Equals(section.Name.ToString()))
                    {
                        break;
                    }
                }
            }
            string exMessage = null;
            if (null == section)
            {
                exMessage = string.Format("Section {0} was not found in file {1}",
                                    sectionName, fileLocation);
                throw new Exception(exMessage);
            }

            XElement keySection = section;
            if (null != subsectionName)
            {
                keySection = section.Element(subsectionName);

                if (null == keySection)
                {
                    exMessage = string.Format("subSection {0} was not found in file {1}",
                                  subsectionName, fileLocation);
                    return false;
                }
            }

            XElement matchedElement = null;
            nodes =
                from node in keySection.DescendantNodes()
                select node;
            foreach (XNode node in nodes)
            {
                if (node is XElement)
                {
                    XElement element = node as XElement;
                    if (null != element.FirstAttribute)
                    {
                        if (keyName.Equals(element.FirstAttribute.Value))
                        {
                            matchedElement = node as XElement; // FindMatch(node as XElement, nodeName);
                            break;
                        }
                    }
                }
            }
            if (null == matchedElement)
            {
                exMessage = string.Format("keyName {0} was not found in file {1}",
                    keyName, fileLocation);
                return false;
            }

            XAttribute attrib = matchedElement.LastAttribute;
            attrib.Value = newValue;

            doc.Save(fileLocation);
            return true;
        }

        /// <summary>
        /// Add a new configuration value in the config file
        /// </summary>
        /// <param name="fileLocation"></param>
        /// <param name="sectionName"></param>
        /// <param name="subsectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="newValue"></param>
        /// <returns></returns>
        public static bool AddConfigValue(string fileLocation, string sectionName, string keyName, string newValue)
        {
            XDocument doc = XDocument.Load(fileLocation);
            XElement section = null;
            IEnumerable<XNode> nodes =
                from node in doc.DescendantNodes()
                select node;

            foreach (XNode node in nodes)
            {
                if (node is XElement)
                {
                    section = node as XElement;
                    if (sectionName.Equals(section.Name.ToString()))
                    {
                        break;
                    }
                }
            }

            string exMessage = null;
            if (null == section)
            {
                exMessage = string.Format("Section {0} was not found in file {1}",
                                    sectionName, fileLocation);
                throw new Exception(exMessage);
            }

            XElement element = new XElement("add", new XAttribute("key", keyName), new XAttribute("value", newValue));
            Console.WriteLine("Adding config key {0} with value {1} under section {2} to {3}", keyName, newValue, sectionName, fileLocation);
            section.Add(element);
            doc.Save(fileLocation);
            return true;
        }

        /// <summary>
        /// Add a new configuration value in the config file
        /// </summary>
        /// <param name="fileLocation"></param>
        /// <param name="sectionName"></param>
        /// <param name="subsectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="newValue"></param>
        /// <returns></returns>
        public static bool RemoveConfigValue(string fileLocation, string sectionName, string keyName)
        {
            XDocument doc = XDocument.Load(fileLocation);
            XElement section = null;
            IEnumerable<XNode> nodes =
                from node in doc.DescendantNodes()
                select node;

            foreach (XNode node in nodes)
            {
                if (node is XElement)
                {
                    section = node as XElement;
                    if (sectionName.Equals(section.Name.ToString()))
                    {
                        break;
                    }
                }
            }

            string exMessage = null;
            if (null == section)
            {
                exMessage = string.Format("Section {0} was not found in file {1}",
                                    sectionName, fileLocation);
                throw new Exception(exMessage);
            }

            XElement matchedElement = null;
            nodes =
                from node in section.DescendantNodes()
                select node;

            foreach (XNode node in nodes)
            {
                if (node is XElement)
                {
                    XElement element = node as XElement;
                    if (null != element.FirstAttribute)
                    {
                        if (keyName.Equals(element.FirstAttribute.Value))
                        {
                            matchedElement = node as XElement; // FindMatch(node as XElement, nodeName);
                            break;
                        }
                    }
                }
            }
            if (null == matchedElement)
            {
                exMessage = string.Format("Config key {0} under section {1} was not found in file {2}",
                                    keyName, sectionName, fileLocation);
                throw new Exception(exMessage);
            }
            Console.WriteLine("Removing config key {0} under section {1} from {2}", keyName, sectionName, fileLocation);
            matchedElement.Remove();
            doc.Save(fileLocation);
            return true;
        }
    }
}